﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Lesson6
{
    #region 静态
    // 静态成员
    //   静态关键字 static
    //   用static修饰的成员变量、方法、属性等都称为静态成员

    // 静态成员的特点是：直接用类名点出使用

    // 自定义静态成员
    class Test
    {
        // 静态成员变量
        static public float PI = 3.141592653f;

        // 成员变量
        public int length = 100;

        // 静态成员方法
        public static float CalcCircle(float r)  // 圆面积
        {
            // πr²
            return PI * r * r;
        }

        // 成员方法
        public void Fun()
        {
            Console.WriteLine("123");
        }

        // 静态成员的特点
        // 程序开始运行时，就会分配内存空间，所以能直接点出来使用
        // 静态成员是程序运行开始到结束都会存在的
        // 静态成员具有唯一性

        public static void TestPlay()
        {
            // 静态函数中不能使用非静态成员
            // 成员变量只能将对象实例化出来后 才能点出来使用 不能无中生有
            //Console.WriteLine(length);   // 不能直接访问，报错
            Test t = new Test();
            Console.WriteLine(t.length);
        }

        public void TestFun()
        {
            // 非静态函数可以使用静态成员
            Console.WriteLine(PI);
        }

        // 静态成员的作用
        //   静态变量：常用唯一变量的声明   方便别人获取对象声明
        //   静态方法：常用的唯一的方法声明  常用的工具类、数学计算相关函数

        // 常量和静态变量
        // const（常量） 可以理解为特殊的static（静态）
        // 相同点
        //  都可以通过类名点出使用
        //  不同点
        //  - const必须初始化，不能修改， 而static没有这个规则
        //  - const只能修饰变量， 而static可以修饰很多
        //  - const 一定是写在访问修饰符后面的，而static没有这个要求
        public const float G = 9.8f;
    }

    // 静态类
    //  用static修饰的类
    //  只能包含静态成员
    //  不能被实例化

    // 作用： 将常用的静态成员写在静态类中  方便使用， 静态类下不能被实例化，更能体现工具类的 唯一性
    //  比如 Console就是一个静态类
    static class TestStatic
    {
        // 静态成员变量
        public static int index = 0;
        //public int a = 1;                   // 报错

        public static void Play()
        {
            Console.WriteLine(index);
        }

        // 静态成员属性
        public static int Index
        {
            get;
            set;
        }


    }

    // 静态构造函数
    // 特点
    //   1、静态类和普通类都可以有
    //   2、不能使用访问修饰符
    //   3、不能有参数
    //   4、只会自动调用一次
    // 作用
    //   在静态构造函数中初始化 静态变量

    // 静态类中的静态构造函数
    static class StaticFunc
    {
        public static int testNum = 100;
        public static int testNum2 = 100;

        // 只会在函数初始化的时候执行一次，类似 java 中的 static静态代码块
        static StaticFunc()
        {
            Console.WriteLine(testNum);
            Console.WriteLine("静态构造函数");
        }
    }

    // 普通类中的静态构造函数
    class TestNormal
    {
        public int value = 1;

        static TestNormal()
        {
            Console.WriteLine("静态构造");
        }

        // 上面的就是静态构造函数，以下这个不构成重载

        public TestNormal()
        {
            Console.WriteLine("普通构造");
        }

        public void Func1()
        {

        }

        public void Func2()
        {

        }
    }
    #endregion

    #region 拓展方法
    // 拓展方法基本概念
    //   为现有非静态 变量类型 添加新方法
    //  作用：
    //    提升程序拓展性
    //    不需要在对象中重新写方法
    //    不需要继承来添加方法
    //    为别人封装的类型写额外的方法
    //  特点
    //    1、一定是写在静态类中
    //    2、一定是个静态函数
    //    3、第一个参数为拓展目标
    //    4、第一个参数用this修饰

    // 基本语法：
    //   访问修饰符 static 返回值 函数名(this 拓展类名 参数名, 参数类型 参数名, ...)
    static class Tools
    {
        // 为 int 类型添加新方法，相当于 为int拓展了一个成员方法
        // 成员方法 是需要 实例化对象后才能使用的
        // value代表 使用该方法的 实例化对象
        public static void SpeakValue(this int value)
        {
            // 拓展方法的逻辑
            Console.WriteLine("为int 拓展的方法" + value);
        }

        // 带参数的拓展方法
        public static void SpeakInfo(this string str, string str1, string str2)
        {
            // 拓展方法的逻辑
            Console.WriteLine("为 string 拓展的方法");
            Console.WriteLine("调用方法的对象" + str);
            Console.WriteLine("传的参数"+ str1 + str2);
        }

        // 为自定义类 TestNormalt拓展方法
        public static void Func3(this TestNormal n)         // 拓展的方法不能与原类中的方法重名，不然就无效
        {
            Console.WriteLine("为TestNormal拓展的方法Func3");
        }
        
        // 静态类不能拓展
    }
    #endregion

    #region 运算符重载
    // 概念
    //  让自定义类和结构体能够使用运算符
    //  关键字 operator
    // 特点
    //  一定是一个公共的静态方法
    //  返回值写在operator前
    //  逻辑处理自定义

    // 作用： 让自定义类和结构体对象可以进行运算
    // 注意： 条件运算符要成对实现，一个符号可以多个重载， 不能使用ref和out

    // 语法
    //  public static 返回类型 operator 运算符(参数列表)

    // 实现
    class Point
    {
        public int x;
        public int y;

        // 运算符重载
        public static Point operator +(Point p1, Point p2)
        {
            Point p  = new Point();
            p.x = p1.x + p2.x;
            p.y = p1.y + p2.y;
            return p;
        }
        // 多个重载
        public static Point operator +(Point p1, int i)
        {
            Point p = new Point();
            p.x = p1.x + i;
            p.y = p1.y + i;
            return p;
        }

        // 可重载的运算符  需要注意符号需要两个参数还是一个参数
        //  算术运算符 两个参数： + - * / %    一个参数：++ -- 
        public static Point operator -(Point p1, int i)
        {
            return null;
        }
        public static Point operator ++(Point p1)
        {
            return null;
        }
        //  逻辑运算符 ! (一个参数)
        public static bool operator !(Point p1)
        {
            return false;
        }
        // 位运算符 两个参数：| &  ^  <<    >>   一个参数： ~
        // 条件运算符：返回值一般是bool值 也可以是其他的  相关符号必须配对实现
        // 两个参数：( >  < )   ( >=  <= )  ( ==  != )

        // 不可重载的运算符
        //   逻辑与（&&） 逻辑或（||）
        //   索引符 []
        //   强转运算符   ()
        //   特殊运算符  (点.)  (三目运算符 ? : )  (赋值符号 =)

    }


    #endregion


    #region 内部类、分部类

    // 内部类： 一个类中再声明一个类
    //    使用时要包裹者点出自己
    //    访问修饰符作用很大
    class Person
    {
        public class Body
        {
            // 默认是私有的
            class Arm
            {

            }
        }
    }

    // 分部类
    //  概念：把一个类分成几部分声明
    //  关键字： partial
    // 作用： 分部描述一个类， 增加程序的拓展性
    // 注意： 分部类可以写在多个脚本文件中，分部类的访问修饰符要一致，分部类中不能有重复成员
    // 例：
    partial class Student
    {
        public bool sex;
        public int age;
    }
    partial class Student
    {
        public string name;

        // 分部方法 先声明
        partial void SomeMethod();
    }


    // 分部方法：也要加关键字 partial
    //   将方法的声明和实现分离
    //  注意：不能加访问修饰符，默认私有
    //        只能在分部类中声明
    //        返回值只能是void
    //        可以有参数但不用 out 关键字
    partial class Student
    {
        // 分部方法 实现
        partial void SomeMethod()
        {
            Console.WriteLine("实现逻辑");
        }
    }


    #endregion

    internal class Program
    {
        static void Main(string[] args)
        {
            // 静态成员的使用
            Console.WriteLine(Test.PI);
            Console.WriteLine(Test.CalcCircle(5));

            Console.WriteLine(Test.G);

            Console.WriteLine(StaticFunc.testNum);  // 静态类不能实例化
            Console.WriteLine(StaticFunc.testNum2);  // 访问多少次，静态构造函数只执行一次


            
            TestNormal t = new TestNormal();   
            Console.WriteLine(t.value);  
            TestNormal t2 = new TestNormal();   // 普通类实例化多次，静态构造函数只执行一次


            // 拓展方法的使用
            int i = 10;
            i.SpeakValue();
            string str = "fist";
            str.SpeakInfo("mb", "ddd");

            TestNormal test = new TestNormal();
            test.Func3();

            // 重载运算符的使用
            Point p = new Point();
            p.x = 1;
            p.y = 2;
            Point p2 = new Point();
            p2.x = 3;
            p2.y = 4;

            Point p3 = p + p2;  // 重载运算符后，就可以相加了
            Point p4 = p + 2;   // 参数不同类型

            // 实例化内部类
            Person p5 = new Person();
            Person.Body p6 = new Person.Body();
            //Person.Body.Arm    // 报错，  实例化不了私有的
        }
    }
}
